
//
// 110515 - AH - (Opera) Created.
// 110606a- AH - (Garage) Missing java doc.
// 110606b- AH - (Garage) Uses new RetrievealEvent types LEVEL and TURN.
// 120108 - AH - (Hector) Changed name from WheelProcessing since 
//               WheelProcessing now will be an abstract concept.
// 120117 - AH - (Huset) Deprecated, now this is moved to motor as part of
//               new PassingStrategy logic.
//

package org.soekrat.engine.motor.passingstrategies;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.soekrat.engine.forest.Forest;
import org.soekrat.engine.mine.Mine;
import org.soekrat.engine.motor.ConversationElement;
import org.soekrat.engine.motor.Motor;
import org.soekrat.engine.motor.WheelProcessing;
import org.soekrat.engine.network.Network;
import org.soekrat.engine.ontology.OntologyDatastructure;
import org.soekrat.engine.visitor.Input;
import org.soekrat.engine.visitor.SplitScale;
import org.soekrat.engine.wheel.Wheel;
import org.soekrat.engine.wheel.ontology.Ontology;
import org.soekrat.engine.wheel.retrieval.RetrievalEvent;
import org.soekrat.engine.wheel.retrieval.RetrievalEventType;

/**
 * <p>
 *   Process input from visitor by going through levels and turning the 
 *   {@link Wheel}.
 * </p>
 * <p>
 *   This is pretty much the hearth (yea I don't mean heart, go to Wikipedia 
 *   silly) of Soekrat...
 * </p>
 * @author Arne Halvorsen (AH)
 * @author Laetitia Le Chatton (LLC)
 * @deprecated
 */
@Deprecated
public final class SequenceWheelProcessing extends WheelProcessing 
{
  //private int m_scanAndPaintCount=-1;
  
  private int m_turns=-1;
  
  private List<Class<?>> m_sequence=new ArrayList<Class<?>>();
  
  //
  
  private final Wheel m_wheel;
  
  //private final int m_turns;
  
  /**
   * <p>
   *   Creates instance for factory use only.
   * </p>
   */
  public SequenceWheelProcessing(){ m_wheel=null; }
  
  /**
   * <p>
   *   Creates instance for factory use only.
   * </p>
   */
  public SequenceWheelProcessing(Motor motor){ m_wheel=motor.getWheel(); }
  
  /**
   * <p>
   *   Sets sequences of ontologies (represented by their classes) to use.
   * </p>
   * @param oclasses Classes of ontologies.
   */
  public void setSequence(List<Class<?>> oclasses)
  {
    if (oclasses==null)
    {
      throw new NullPointerException("oclasses");
    }
    
    m_sequence.addAll(oclasses);
  }
  
  /**
   * <p>
   *   Constructor.
   * </p>
   * @param wheel {@link Wheel}.
   * @param turns Number of wheel turns to make.
   */
  /*
  public SequenceWheelProcessing(Wheel wheel, int turns)
  {
    if (wheel==null)
    {
      throw new NullPointerException("wheel");  
    }
    
    m_wheel=wheel;
    m_turns=(turns<1) ? getNumberOfTurns(m_wheel) : turns;
  }
  */
  
  ////////////////////////////////////////////////////////////////////////////
  
  /*
  public WheelProcessing create(Motor motor, MotorConfiguration mc)
  {
    int turns=mc.getTurnCount();
    Wheel wheel=motor.getWheel();
    return new SequenceWheelProcessing(wheel, turns);
  }
  */
  
  public WheelProcessing create(Motor motor)
  {
    SequenceWheelProcessing retVal=new SequenceWheelProcessing(motor);
    retVal.setSequence(m_sequence);
    retVal.setTurnCount(m_turns);
    return retVal;
  }
  
  /**
   * <p>
   *   Sets the number of turns.
   * </p>
   * @param n Count to set-
   * @return {@code this}.
   * @throws IllegalArgumentException If {@code n<1}.
   */
  public SequenceWheelProcessing setTurnCount(int n)
  {
    m_turns=n;
    return this;
  }
  
  /**
   * <p>
   *   Gets turns to be done of the wheel.
   * </p>
   * @return Turn.
   */
  public int getTurnCount(){ return m_turns==-1 ? 1 : m_turns; } 
  
  /*
  public WheelProcessing create(Motor motor, MotorConfiguration mc)
  {
    int turns=mc.getTurnCount();
    Wheel wheel=motor.getWheel();
    return new SequenceWheelProcessing(wheel, turns);
  }
  */
  
  /**
   * <p>
   *   Process.
   * </p>
   * @param ce {@link ConversationElement} being processed.
   * @param ss Input form visitor.
   */
  public RetrievalEvent scanAndPaint(ConversationElement ce, SplitScale ss)
  { 
    if (m_wheel==null)
    {
      throw new IllegalStateException("factory object!");  
    }
    
    if (ce==null)
    {
      throw new NullPointerException("ce");
    }
    if (ss==null)
    {
      throw new NullPointerException("ss");
    }
    
    rinse();
    
    boolean done=false;
    
    RetrievalEvent root=new RetrievalEvent();
    
    RetrievalEvent prev=root;
    
    int n=ss.getLevelCount();
    
    for (int i=0; i<n && !done; i++)
    {
      Input level=ss.getLevel(i);
      
      RetrievalEvent ret=new RetrievalEvent(""+i+" | "+level, 
        RetrievalEventType.LEVEL);
      
      prev.addTail(ret);
      
      done=level(level, ce, ret);
      
      prev=ret.getLast();
    }
    
    return root;
  }
  
  private void rinse()
  {
    int n=m_wheel.getNumberOfOntologies();
    for (int i=0; i<n; i++)
    {
      Ontology spoke=m_wheel.getOntology(i);
      spoke.rinse();
    }
  }
  
  /**
   * <p>
   *   TODO
   * </p>
   * @param wheel
   * @param level
   * @param ce
   * @return {@code false} all ontologies passed else {@code true}.
   */
  private boolean level(Input level, ConversationElement ce, 
    RetrievalEvent prev)
  {
    ce.removeAttribute("pass-count");
 
    ce.setAttribute("input", level);
    
    int turns=getTurnCount();
    for (int i=0; i<turns; i++)
    {
      RetrievalEvent turn=new RetrievalEvent(""+(i+1), RetrievalEventType.TURN);
      
      prev.addTail(turn);
      
      turn(m_wheel, ce, turn);
    }
    
    Integer passCount=(Integer)ce.getAttribute("pass-count");
    passCount=(passCount==null) ? 0 : passCount;
    
    int totOntologies=m_wheel.getOntologiesForTurn().size()*m_turns;
    
    if (passCount==totOntologies) 
    {
      return false;
    }
    else
    {
      return true;
    }
  }
  
  private void turn(Wheel wheel, ConversationElement ce, RetrievalEvent prev)
  {
    List<Ontology> spokes=wheel.getOntologiesForTurn();
    for (Ontology spoke : spokes)
    {
      RetrievalEvent tail=spoke.scanAndPaint(ce);
      
      prev.addTail(tail);
      prev=tail;
    }
  }
  
  /**
   * <p>
   *   Gets the default configuration.
   * </p>
   * @return Default
   *         {@link CopyOfMotorConfiguration}.
   */
  public static SequenceWheelProcessing createDefaultConfig(Motor motor)
  {
    SequenceWheelProcessing retVal=new SequenceWheelProcessing(motor);
    //retVal.setTurnCount(1);
    
    List<Class<?>> oclasses=new ArrayList<Class<?>>();
    oclasses.add(Mine.class);
    oclasses.add(Forest.class);
    oclasses.add(Network.class);
    Collections.shuffle(oclasses);
    
    retVal.setSequence(oclasses);
    
    return retVal;
  }
  
  /**
   * <p>
   *   Gets sequence of ontology classes.
   * </p>
   * @return Sequence of classes. Default is a sequence of a single element,
   *         the {@code Forest class}.
   */
  public List<Class<?>> getSequence()
  {
    return new ArrayList<Class<?>>(m_sequence); 
  }
  
  /**
   * <p>
   *   Gets names on
   *   {@link OntologyDatastructure ontologies} in sequence in sequence. 
   * </p>
   * @return Names.
   */
  public String[] getOntologyNamesInSequence()
  {
    int n=m_sequence.size();
    String[] retVal=new String[n];
    for (int i=0; i<n; i++)
    {
      Class<?> c=m_sequence.get(i);
      retVal[i]=c.getSimpleName();
    }
    return retVal;
  }
  
  /**
   * <p>
   *   Adds to the ontology sequence.
   * </p>
   * @param name Simple class name on ontology yo add.
   * @return {@code this}.
   * @throws IllegalArgumentException If ontology not found.
   */
  public SequenceWheelProcessing addOntology(String name)
  {
    if (name==null)
    {
      throw new NullPointerException("name");
    }
    
    m_sequence.add(OntologyDatastructure.getOntologyClass(name));
    return this;
  }
  
  /*
  private int getNumberOfTurns(Wheel wheel)
  {
    int n=wheel.getNumberOfSpokes();
    Random rnd=new Random();
    return rnd.nextInt(n)+1;
  }
  */
  
}
